// 基于环形队列的生产消费模型
#pragma once

#include <iostream>
#include <vector>
#include "Sem.hpp"
#include "Mutex.hpp"

const static int gcap = 5;

using namespace SemMoudle;
using namespace MutexModule;

template <typename T>
class RingQueue
{
public:
    RingQueue(int cap = gcap)
        : _rq(cap),
          _cap(cap),
          _black_sem(cap),
          _p_step(0),
          _data_sem(0),
          _c_step(0)
    {
    }

    void Equeue(const T &in)
    {
        // 生产者
        // 1. 申请空位置信号量(资源的预定机制)
        _black_sem.P();

        {   // 先把资源瓜分了, 再串型式的申请锁
            LockGuard lockguard(_pmutex);
            // 2. 生产
            _rq[_p_step] = in;
            // 3. 更新下标
            ++_p_step;
            // 4. 维持环形特性
            _p_step %= _cap;
        }

        // 5. 通知数据信号量+1
        _data_sem.V();
    }

    void Pop(T *out)
    {
        // 消费者
        // 1. 申请信号量
        _data_sem.P();

        {
            LockGuard lockguard(_cmutex);
            // 2. 消费
            *out = _rq[_c_step];
            // 3. 更新下标
            ++_c_step;
            // 4. 维持环状特性
            _c_step %= _cap;
        }

        // 通知空格信号
        _black_sem.V();
    }

    ~RingQueue() {}

private:
    std::vector<T> _rq;
    int _cap; // 容量

    // 生产者
    Sem _black_sem; // 空位置
    int _p_step;
    // 消费者
    Sem _data_sem; // 数据
    int _c_step;

    // 维护多生产多消费 -> 锁
    Mutex _cmutex;
    Mutex _pmutex;
};